package top.aigoo.project01.utils;

import com.mysql.jdbc.util.Base64Decoder;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import java.io.*;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * @Description: DES是一种对称的加密算法，所谓对称加密算法既:加密和解密使用相同的秘钥的算法
 * @Author: Mr.OYSHUO.欧阳大叔  mail:1642302522@qq.com
 * @Version 1.0.0
 * @Date: 2021/9/11 12:32
 */

public class DESUtil {
    private static Key key;
    //设置秘钥key
    private static String KEY_STR = "myKey";
    /**
     * 默认编码
     */
    private static final String CHARSETNAME = "UTF-8";
    /**
     * 密钥算法
     */
    private static final String ALGORITHM = "DES";

    /**
     * 生成key
     *
     * @param password 加密秘钥
     * @return
     */
    private static Key generateKey(String password) {
        //如果没有传递进来加密秘钥，则使用类默认秘钥

        if (password == null ||password.equals("")) {
            password = KEY_STR;
        }
        try {
            //生成DES算法对象
            KeyGenerator generator = KeyGenerator.getInstance(ALGORITHM);
            //运用SHA1安全策略
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            //设置上秘钥种子
            secureRandom.setSeed(password.getBytes());
            //初始化基于SHA1的算法对象
            generator.init(secureRandom);
            //生成秘钥对象
            key = generator.generateKey();

            generator = null;
            return key;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 生成加密信息
     *
     * @param str 待加密的字符串
     * @return 加密后信息
     */
    public static String getEncryptString(String str) {
        //基于BASE64编码，接收byte[]并转换成String
        BASE64Encoder base64encoder = new BASE64Encoder();
        try {
            //按照utf8编码
            byte[] bytes = str.getBytes(CHARSETNAME);
            //获取加密对象
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            //初始化密码信息
            cipher.init(Cipher.ENCRYPT_MODE, generateKey(""));
            //加密
            byte[] doFinal = cipher.doFinal(bytes);
            //byte[] to encode 好的String并返回
            return base64encoder.encode(doFinal);
        } catch (Exception e) {
            // TODO: handle exception
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取解密之后的信息
     *
     * @param str 加密的信息
     * @return 解密后的信息
     */
    public static String getDecryptString(String str) {
        //基于BASE64编码，接收byte[]并转换成String
        BASE64Decoder base64decoder = new BASE64Decoder();
        try {
            //将字符串decode成byte[]
            byte[] bytes = base64decoder.decodeBuffer(str);
            //获取解密对象
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            //初始化解密信息
            cipher.init(Cipher.DECRYPT_MODE, generateKey(""));
            //解密
            byte[] doFinal = cipher.doFinal(bytes);
            //返回解密之后的信息
            return new String(doFinal, CHARSETNAME);
        } catch (Exception e) {
            // TODO: handle exception
            throw new RuntimeException(e);
        }
    }

    /**
     * DES加密字符串
     *
     * @param password 加密密码，长度不小于8位
     * @param data     待加密字符串
     * @return 加密后字符串
     */
    public static String encrypt(String password, String data) {

        if (password == null || password.length() < 2) {
            throw new RuntimeException("加密失败,加密密码key不能小于8位");
        }
        if (data == null) {
            return null;
        }

        //获取加密对象
        try {
            byte[] bytes = data.getBytes(CHARSETNAME);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            //初始化密码信息
            cipher.init(Cipher.ENCRYPT_MODE, generateKey(password));
            //加密
            byte[] doFinal = cipher.doFinal(bytes);
            //byte[] to encode 好的String并返回
            return new String(Base64.getEncoder().encode(doFinal));
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());

        }

    }

    /**
     * DES解密字符串
     *
     * @param password 解密密码，长度不小于8位
     * @param data     待解密字符串
     * @return 解密后内容
     */
    public static String decrypt(String password, String data) {
        //1.先对数据进行校验
        if (password == null || password.length() < 2) {
            throw new RuntimeException("加密失败,加密密码key不能小于8位");
        }
        if (data == null) {
            return null;
        }

        //3. 进行解密
        try {
            //将字符串decode成byte[]
            byte[] bytes = Base64.getDecoder().decode(data.getBytes(CHARSETNAME));
            //获取解密对象
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            //初始化密码信息
            cipher.init(Cipher.DECRYPT_MODE, generateKey(password));
            //加密
            byte[] doFinal = cipher.doFinal(bytes);
            //byte[] to encode 好的String并返回
            return new String(doFinal, CHARSETNAME);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());

        }

    }

    /**
     * DES加密文件
     *
     * @param srcFile  待加密的文件
     * @param destFile 加密后存放的文件路径
     * @return 加密后的文件路径
     */
    public static String encryptFile(String password, String srcFile, String destFile) {

        if (password == null || password.length() < 8) {
            throw new RuntimeException("加密失败，key不能小于8位");
        }
        try {

            //IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSETNAME));
            //获取加密对象
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            //初始化加密信息
            cipher.init(Cipher.ENCRYPT_MODE, generateKey(password));
            //读取文件流
            InputStream is = new FileInputStream(srcFile);
            //设定文件输出流
            OutputStream out = new FileOutputStream(destFile);
            //加密
            CipherInputStream cis = new CipherInputStream(is, cipher);

            byte[] buffer = new byte[1024];
            int r;
            //加密后字符输出到输出文件
            while ((r = cis.read(buffer)) > 0) {
                out.write(buffer, 0, r);
            }

            cis.close();

            is.close();

            out.close();

            return destFile;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * DES解密文件
     *
     * @param srcFile  已加密的文件
     * @param destFile 解密后存放的文件路径
     * @return 解密后的文件路径
     */
    public static String decryptFile(String password, String srcFile, String destFile) {
        if (password == null || password.length() < 8) {
            throw new RuntimeException("加密失败，key不能小于8位");
        }
        try {

            File file = new File(destFile);
            if (!file.exists()) {
                file.getParentFile().mkdirs();
                file.createNewFile();
            }
            //IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSETNAME));

            Cipher cipher = Cipher.getInstance(ALGORITHM);
            //cipher.init(Cipher.DECRYPT_MODE, generateKey(password), iv);
            cipher.init(Cipher.DECRYPT_MODE, generateKey(password));

            InputStream is = new FileInputStream(srcFile);

            OutputStream out = new FileOutputStream(destFile);

            CipherOutputStream cos = new CipherOutputStream(out, cipher);

            byte[] buffer = new byte[1024];
            int r;
            while ((r = is.read(buffer)) >= 0) {
                cos.write(buffer, 0, r);
            }
            cos.close();
            is.close();
            out.close();
            return destFile;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }


    public static void main(String[] args) {
        //System.out.println("root加密后:"+getEncryptString("root"));
        //System.out.println(getEncryptString("230230"));
        //System.out.println(getEncryptString("wxd7f6c5b8899fba83"));
       // System.out.println(getEncryptString("665ae80dba31fc91ab6191e7da4d676d"));
        System.out.println("用户名加密后:"+getEncryptString("luo"));
        System.out.println("密码加密后:"+getEncryptString("Luo!#*0126"));

        //System.out.println("=====================");
        //System.out.println(encrypt("myKey", "root"));
        //System.out.println(decrypt("myKey", "WnplV/ietfQ="));
    }
}
